#include <QtCore>
#include <QtGui>
#include "include/mainwindow.h"
#include "include/CSplashScreen.h"
#include "include/Preferences.h"
#include "include/licensedialog.h"
#include "include/licensing.h"
#include "include/unittests.h"
#include "include/licenseagreement.h"

#include <QNetworkInterface>

//#include <QtCrypto> //somewhere in the nested libraryes a semicolon is absent

#ifdef MU_LICENSING
#include <qca_core.h>
#include <qca_publickey.h>
#endif

#include <QKeySequence>

#include "include/Preferences.h"
#include "include/mucustomshortcuts.h"
#include <QAction>
#include <QKeySequence>

bool checkLicense();

namespace
{

	QAction* createAction(QString name, QString shortcut)
	{
		QAction* action = new QAction(name, 0);
		action->setShortcut(QKeySequence(shortcut));
		return action;
	}

}

bool checkLicenseAgreement();

int main(int argc, char *argv[])
{
	UnitTests::testMajorSystem();

#ifdef MU_LICENSING
	QCA::Initializer init;
#endif

	QApplication app(argc, argv);

	QCoreApplication::setOrganizationName("MemuSoft");
	QCoreApplication::setOrganizationDomain("memusoft.com");
	QCoreApplication::setApplicationName("Mu");

#ifdef MU_LICENSING
	if (!checkLicenseAgreement())
		return 1;

	if (!checkLicense())
		return 1;
#endif

	class SleeperThread : public QThread
	{
		public:
			static void msleep(unsigned long msecs) {
				QThread::msleep(msecs);
			}
	};

	QPixmap aSplashImage(":/resources/mu.png");

	CSplashScreen* aSplashScreen = new CSplashScreen(aSplashImage);


 #if QT_VERSION >= 0x040600
	if (QIcon::themeName().isEmpty())
		QIcon::setThemeName("mu-theme");
 #endif

	MainWindow window;
	window.show();

	aSplashScreen->show();
//	SleeperThread::msleep(1000);

	delete aSplashScreen;

	DependencyDetector* detect = new DependencyDetector;
	(*detect)();

	return app.exec();
}

#ifdef MU_LICENSING

bool checkLicenseAgreement()
{
	if (!QSettings().value("licenseAgreementV1").toBool())
	{
		LicenseAgreement lic;

		if (!lic.getUserResponse())
		{
			return false;
		}
		else
		{
			QSettings().setValue("licenseAgreementV1", true);
			return true;
		}
	}
	return true;
}

bool matchWithMacs(QString licenseHex)
{
	const QString publicKeyPath = ":/keys/resources/mu_key.pub";
	QResource res(publicKeyPath);

	QByteArray arr(reinterpret_cast<const char*>(res.data()), (int)res.size());

	QCA::ConvertResult convesionResult;
	QCA::PublicKey publicKey = QCA::PublicKey::fromPEM(arr, &convesionResult);

	//looking all network interfaces (maybe it has sense to exclude loopback 00:00... ?)
	foreach (QNetworkInterface interface, QNetworkInterface::allInterfaces())
	{
		if ((interface.flags() & QNetworkInterface::IsLoopBack) == QNetworkInterface::IsLoopBack)
			continue;

		QString macAddress = interface.hardwareAddress().toLower();

		QByteArray license = QByteArray::fromHex(licenseHex.toAscii());

		QCA::SecureArray sa = macAddress.toAscii();
		if (publicKey.verifyMessage(sa, license, QCA::EMSA3_MD5))
		   return true;
	}

	return false;
}



bool checkLicense()
{
	//public key loading
	const QString publicKeyPath = ":/keys/resources/mu_key.pub";
	QResource res(publicKeyPath);

	QByteArray arr(reinterpret_cast<const char*>(res.data()), (int)res.size());

	QCA::ConvertResult convesionResult;
	QCA::PublicKey publicKey = QCA::PublicKey::fromPEM(arr, &convesionResult);

	//TODO: this case is possible if public key was not generated by the dedicated scrypt (keygen.sh)
	//It is suggested to write corresponding unit test to prevent this case in practice
	if (convesionResult != QCA::ConvertGood)
	{
		QMessageBox::critical(0, "Critical Error", "This packages has one of the following problems:\n"\
							  "1. Corrupted public key;\n"\
							  "2. QCA-ossl plugin is not installed;\n"\
							  "3. OpenSSL is not installed.\n"\
							  "Please contact the vendor to fix the problem.");
		return false;
	}

	//checking the license
	const QString snKey = "licenseNumber";

	QString savedSn = QSettings().value(snKey).toString(); //this value will be retrieved from QSettings

	if (matchWithMacs(savedSn))
		return true;

	bool continuing = true;

	while (continuing)
	{
		LicenseDialog dlg;
		dlg.setPublicKey(publicKey);

		if (dlg.exec() == QDialog::Rejected)
			return false;

		QString sn = dlg.serialNumber();

		if (matchWithMacs(sn)) //CorruptedKeyException is not handled here because it can happen only above
		{
			QSettings().setValue(snKey, sn);
			//saving to settings
			return true;
		}
		else
		{
			//NOTE: as improvement we can display error message in the status bar of LicenseDialog
			QMessageBox::critical(0, QMessageBox::tr("License Checking Dialog"), QMessageBox::tr("The license key is incorrect!"));
		}
	}

	return false;
}
#endif